package com.derekandbritt.booST.server;

import java.util.ArrayList;
import java.util.Date;

import javax.jdo.PersistenceManager;

import com.derekandbritt.booST.data.Challenge;
import com.derekandbritt.booST.data.EmotionLevel;
import com.derekandbritt.booST.data.EnergyLevel;
import com.derekandbritt.booST.data.Challenge.Status;

public class ChallengeCalculator {

    private DataManager dataManager;
    private PersistenceManager pm;

    public ChallengeCalculator(DataManager dataManager) {
        this.dataManager = dataManager;
        this.pm = null;
    }
    
    public ChallengeCalculator(DataManager dataManager, PersistenceManager pm) {
        this.dataManager = dataManager;
        this.pm = pm;
    }
    
    public ArrayList<EnergyLevel> evaluateChallenge(Challenge oldChallenge, Challenge newChallenge) {
        
        ArrayList<EnergyLevel> levels = new ArrayList<EnergyLevel>();
        
        String senderId = newChallenge.getSender();
        String receiverId = newChallenge.getReceiver();
        Date currentTime = newChallenge.getLastUpdated();
        
        // newly created challenge
        if(oldChallenge == null) {
            levels.add(createEnergy(senderId, 2, currentTime));
        }
        // status change
        else if(oldChallenge.getStatus() != newChallenge.getStatus()) {
            
            switch(newChallenge.getStatus()) {
                
            // initial state so this shouldn't happen
            case PENDING:
                break;
            
            // receiver accepted the challenge
            case ACCEPTED:
                levels.add(createEnergy(receiverId, 1, currentTime));
                break;
            
            // receiver rejected the challenge
            case REJECTED:
                levels.add(createEnergy(receiverId, -1, currentTime));
                break;
            
            // expired challenge so penalize those who did not participate
            case EXPIRED:
                if(oldChallenge.getStatus() != Status.PENDING) {
                    if(newChallenge.getSenderTime() <= 0)
                        levels.add(createEnergy(senderId, -7, currentTime));
                    if(newChallenge.getReceiverTime() <= 0)
                        levels.add(createEnergy(receiverId, -7, currentTime));
                }
                break;
                
            case COMPLETED:
                
                int senderTime = newChallenge.getSenderTime();
                int receiverTime = newChallenge.getReceiverTime();
                
                double senderBoost = computeBoost(senderId, receiverId, Status.COMPLETED);
                double receiverBoost = computeBoost(receiverId, senderId, Status.COMPLETED);
                
                // COMPETITIVE Challenge
                if(newChallenge.getType() == Challenge.Type.COMPETITIVE) {
                    if(senderTime > receiverTime) {
                        levels.add(createEnergy(receiverId, receiverBoost + 5, currentTime));
                        levels.add(createEnergy(senderId, senderBoost - 5, currentTime));
                    } else {
                        levels.add(createEnergy(senderId, senderBoost + 5, currentTime));
                        levels.add(createEnergy(receiverId, receiverBoost - 5, currentTime));
                    }
                // COOPERATIVE Challenge
                } else {
                    
                    int timeLimit = newChallenge.getTimeLimit();
                    
                    if(senderTime <= timeLimit && receiverTime <= timeLimit) {
                        levels.add(createEnergy(senderId, senderBoost + 5, currentTime));
                        levels.add(createEnergy(receiverId, receiverBoost + 5, currentTime));
                    } else {
                        levels.add(createEnergy(senderId, senderBoost - 5, currentTime));
                        levels.add(createEnergy(receiverId, receiverBoost - 5, currentTime));
                    }
                }
                break;
            
            }
        }
        
        return levels;
    }

    private double computeBoost(String primaryId, String secondaryId, Status status) {
        
        //EmotionLevel primaryEmotion = dataManager.getEmotionLevel(primaryId);
        EmotionLevel secondaryEmotion;
        
        if(pm == null) 
            secondaryEmotion = dataManager.getEmotionLevel(secondaryId);
        else
            secondaryEmotion = dataManager.getEmotionLevel(secondaryId, pm);
        
        //double primaryLevel = (primaryEmotion != null) ? primaryEmotion.getLevel() : 5;
        double secondaryLevel = (secondaryEmotion != null) ? secondaryEmotion.getLevel() : 5;
        
        switch(status) {
            case COMPLETED:
                return 5 - (secondaryLevel * 0.5);
        }
        
        return 0;
    }

    private static EnergyLevel createEnergy(String personId, double level, Date timestamp) {
        EnergyLevel energy = new EnergyLevel(personId, level);
        energy.setTimestamp(timestamp);
        return energy;
    }
    
}
